package com.pdd.commons.utils;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author:liyangpeng
 * @date:2019/1/14 13:59
 */
public class OkHttpUtil {

    private static final Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);
    /**
     * get
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return
     */
    public static String get(String url, Map<String, Object> queries,Map<String,Object> headers,Map<String,String> Authorization){
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.keySet().size() > 0) {
            //参数拼接
            for (Map.Entry<String,Object> entry:queries.entrySet()) {
                if(url.indexOf("?")>0||sb.toString().indexOf("?")>0){
                    sb.append("&" + entry.getKey() + "=" + entry.getValue());
                }else{
                    sb.append("?" + entry.getKey() + "=" + entry.getValue());
                }
            }
        }
        Request request = addHeader(new Request.Builder().url(sb.toString()),headers).build();
        return OkHttpRequestRetBody(request,Authorization);
    }

    /**
     * post
     * @param url    请求的url
     * @param params post form 提交的参数
     * @return
     */
    public static String post(String url, Map<String, Object> params,Map<String,Object> headers,Map<String,String> Authorization){
        //设置参数
        FormBody.Builder builder = SetParam(params);
        //编辑请求
        Request request = addHeader(new Request.Builder().url(url).post(builder.build()),headers).build();
        return OkHttpRequestRetBody(request,Authorization);
    }

    /**
     * post提交json数据
     * @param url
     * @param params
     * @param headers
     * @param Authorization
     * @return
     * @throws
     */
    public static String postJson(String url, JSONObject params, Map<String,Object> headers, Map<String,String> Authorization){
        RequestBody body=RequestBody.create(MediaType.parse("application/json"),params.toJSONString());
        Request request = addHeader(new Request.Builder().url(url).post(body),headers).build();
        return OkHttpRequestRetBody(request,Authorization);
    }

    /**
     * 图片下载工具类
     * @param url
     * @param savePath
     * @return
     */
    public static String downLoadImg(String url,String savePath){
        Request request=new Request.Builder().url(url).build();
        OkHttpClient httpClient=getSSLHttpClient();
        try {
            InputStream inputStream=httpClient.newCall(request).execute().body().byteStream();
            FileOutputStream file=new FileOutputStream(savePath);
            byte [] bt=new byte[2048];
            int len=0;
            while((len=inputStream.read(bt))!=-1){
                file.write(bt,0,len);
            }
            file.flush();
            file.close();
            inputStream.close();
            return "success";
        } catch (IOException e) {
            e.printStackTrace();
            return "error";
        }
    }
    /**
     * OkHttp3 请求返回Response.Body()
     * @param request 请求
     * @return
     */
    public static String OkHttpRequestRetBody(Request request,Map<String,String> Authorization) {
        Response response = null;
        try {
            OkHttpClient okHttpClient=getOkHttpClient(Authorization);
            response = okHttpClient.newCall(request).execute();
            if(response==null){
                logger.info("【OkHttp】发送的请求失败未收到响应");
                return null;
            }
            //请求参数记录
            JSONObject param=new JSONObject();
            if(request.body()!=null){
                if(request.body() instanceof  FormBody){
                    FormBody body = (FormBody) request.body();
                    for (int i = 0; i < body.size(); i++) {
                        param.put(body.encodedName(i),body.encodedValue(i));
                    }
                }
            }
            if (response.isSuccessful()) {
                logger.info("【OkHttp】Request Execute [{}] Successful code:[{}] link:[{}] param:{}",request.method(),response.code(),request.url().toString(),param.toString());
                return response.body().string();
            }else{
                logger.info("【OkHttp】Request Execute [{}] Not Successful code:[{}] link:[{}] param:{}",request.method(),response.code(),request.url().toString(),param.toString());
            }
        } catch (Exception e) {
            logger.error("【OkHttp】Request Execute [{}] Exception code:[{}] Exception Info:{}",request.method(),ExceptionUtils.getStackTrace(e));
            //往上抛出调用接口失败异常
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }
    /**
     * OkHttp请求参数设置
     * @param params
     * @return
     */
    public static FormBody.Builder SetParam(Map<String, Object> params){
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, String.valueOf(params.get(key)));
            }
        }
        return builder;
    }

    /**
     * 设置请求头
     * @param builder
     * @param headers
     * @return
     */
    public static Request.Builder addHeader(Request.Builder builder,Map<String,Object> headers){
        if(headers!=null&&headers.size()>0){
            for (Map.Entry<String,Object> entry: headers.entrySet()) {
                builder.addHeader(entry.getKey(),String.valueOf(entry.getValue()));
            }
        }
        return builder;
    }

    /**
     *生成Http请求客户端可自由装配是否需要请求认证
     * @param Authorization
     * @return
     */
    public static OkHttpClient getOkHttpClient(Map<String,String> Authorization){
        if(Authorization==null){
            //超时时间设置为30秒
            //设置链接池保活时间为1秒
            return getSSLHttpClient();
        }else{
            //添加身份验证请求头
            return new OkHttpClient().newBuilder().authenticator(new Authenticator() {
                @Override
                public Request authenticate(Route route, Response response) throws IOException {
                    String credential = Credentials.basic(Authorization.get("username"), Authorization.get("password"));
                    return response.request().newBuilder().header("Authorization",credential).build();
                }
            }).connectTimeout(30, TimeUnit.SECONDS).connectionPool(new ConnectionPool(5,1,TimeUnit.SECONDS)).build();
        }
    }

    /**
     * 获取信任SSL连接
     * @return
     */
    private static OkHttpClient getSSLHttpClient() {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                    }

                    @Override
                    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                    }

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new java.security.cert.X509Certificate[]{};
                    }
                }
            };
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            //设置超时时间
            builder.connectTimeout(30, TimeUnit.SECONDS).
                    connectionPool(new ConnectionPool(5,1,TimeUnit.SECONDS));
            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
